//! Actor Integration Tests
//! 
//! Tests for the actor system integration and message passing.

use ai_test_platform::{
    actors::{
        test_suite::TestSuiteActor,
        session::SessionActor,
        plugin::PluginActor,
        ai_orchestration::AIOrchestrationActor,
        report::ReportActor,
        messages::*,
    },
    models::{
        testcase::TestCase,
        config::TestConfig,
        Value, ValueMap,
    },
};
use coerce::actor::system::ActorSystem;
use coerce::actor::IntoActor;
use coerce::actor::scheduler::ActorType;
use std::collections::HashMap;
use tokio;
use uuid::Uuid;
use chrono;

#[tokio::test]
async fn test_actor_system_initialization() {
    // Create actor system
    let system = ActorSystem::new();
    
    // Create actors using the correct API
    let plugin_actor = system
        .new_actor("plugin".to_string(), PluginActor::new(), ActorType::Tracked)
        .await
        .expect("Failed to create plugin actor");

    let ai_actor = system
        .new_actor("ai".to_string(), AIOrchestrationActor::new(), ActorType::Tracked)
        .await
        .expect("Failed to create AI actor");

    let report_actor = system
        .new_actor("report".to_string(), ReportActor::new(), ActorType::Tracked)
        .await
        .expect("Failed to create report actor");

    let test_suite_actor = system
        .new_actor(
            "test_suite".to_string(),
            TestSuiteActor::new(plugin_actor.clone().into(), ai_actor.clone().into(), report_actor.clone().into()),
            ActorType::Tracked,
        )
        .await
        .expect("Failed to create test suite actor");
    
    // Test basic actor communication
    let response = test_suite_actor
        .send(TestSuiteMessage::ListSuites)
        .await
        .expect("Failed to send message");
    
    match response {
        TestSuiteResponse::SuiteList { suites } => {
            assert_eq!(suites.len(), 0);
        }
        _ => panic!("Unexpected response type"),
    }
    
    // Shutdown system
    system.shutdown().await;
}

#[tokio::test]
async fn test_session_actor_lifecycle() {
    let system = ActorSystem::new();
    
    // Create session actor
    let session_id = Uuid::new_v4();
    let session_actor = system
        .new_actor(
            format!("session_{}", session_id),
            SessionActor::new(session_id, None, None, None),
            ActorType::Tracked,
        )
        .await
        .expect("Failed to create session actor");
    
    // Create a test case
    let test_case = TestCase::new(TestConfig::new("test_case".to_string()));
    let parameters: ValueMap = HashMap::new();
    
    // Start session
    let response = session_actor
        .send(SessionMessage::StartSession {
            test_case,
            parameters,
        })
        .await
        .expect("Failed to send start session message");
    
    match response {
        SessionResponse::SessionStarted { session_id: returned_id } => {
            assert_eq!(returned_id, session_id);
        }
        _ => panic!("Unexpected response type: {:?}", response),
    }
    
    // Get session summary
    let response = session_actor
        .send(SessionMessage::GetSessionSummary)
        .await
        .expect("Failed to send get summary message");
    
    match response {
        SessionResponse::SessionSummary { summary: _ } => {
            // Session summary should be available
        }
        _ => panic!("Unexpected response type: {:?}", response),
    }
    
    // Stop session
    let response = session_actor
        .send(SessionMessage::StopSession)
        .await
        .expect("Failed to send stop session message");
    
    match response {
        SessionResponse::SessionCompleted { session_id: returned_id, summary: _ } => {
            assert_eq!(returned_id, session_id);
        }
        _ => panic!("Unexpected response type: {:?}", response),
    }
    
    system.shutdown().await;
}

#[tokio::test]
async fn test_plugin_actor_basic_operations() {
    let system = ActorSystem::new();
    
    let plugin_actor = system
        .new_actor("plugin".to_string(), PluginActor::new(), ActorType::Tracked)
        .await
        .expect("Failed to create plugin actor");
    
    // List plugins (should be empty initially)
    let response = plugin_actor
        .send(PluginMessage::ListPlugins)
        .await
        .expect("Failed to send list plugins message");
    
    match response {
        PluginResponse::PluginList { plugins } => {
            assert_eq!(plugins.len(), 0);
        }
        _ => panic!("Unexpected response type: {:?}", response),
    }
    
    system.shutdown().await;
}

#[tokio::test]
async fn test_ai_orchestration_actor() {
    let system = ActorSystem::new();
    
    let ai_actor = system
        .new_actor("ai".to_string(), AIOrchestrationActor::new(), ActorType::Tracked)
        .await
        .expect("Failed to create AI actor");
    
    // Test AI prompt processing
    let prompt = ai_test_platform::models::ai::AIPrompt {
        id: Uuid::new_v4(),
        template: "Generate a simple test case".to_string(),
        variables: HashMap::new(),
        prompt_type: ai_test_platform::models::ai::AIPromptType::TestGeneration,
        created_at: chrono::Utc::now(),
    };
    
    let response = ai_actor
        .send(AIMessage::ProcessPrompt { prompt })
        .await
        .expect("Failed to send AI prompt message");
    
    // Since we don't have a real AI service, expect an error
    match response {
        AIResponse::Error { message: _ } => {
            // Expected since no real AI service is configured
        }
        _ => {
            // If we get a successful response, that's also fine for testing
        }
    }
    
    system.shutdown().await;
}

#[tokio::test]
async fn test_report_actor_operations() {
    let system = ActorSystem::new();
    
    let report_actor = system
        .new_actor("report".to_string(), ReportActor::new(), ActorType::Tracked)
        .await
        .expect("Failed to create report actor");
    
    // Get statistics (should be empty initially)
    let response = report_actor
        .send(ReportMessage::GetStatistics)
        .await
        .expect("Failed to send get statistics message");
    
    match response {
        ReportResponse::Statistics { stats } => {
            // Should have some basic statistics structure
            assert!(stats.is_empty() || !stats.is_empty()); // Just check it's a valid map
        }
        _ => panic!("Unexpected response type: {:?}", response),
    }
    
    system.shutdown().await;
}
